package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.ISysSsoService;
import com.ruoyi.system.utils.HMACSHA1Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;

@Service
public class SysSsoServiceImpl implements ISysSsoService {
    private static final Logger log = LoggerFactory.getLogger(SysSsoServiceImpl.class);

    @Value("${sso.third-party.appId}")
    private String appId;

    @Value("${sso.third-party.appKey}")
    private String appKey;

    @Value("${sso.third-party.tokenUrl}")
    private String tokenUrl;

    @Value("${sso.third-party.userInfoUrl}")
    private String userInfoUrl;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysLoginService loginService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String processSsoLogin(String ticket) throws Exception {
        // 1. 获取第三方 AccessToken
        String accessToken = getThirdPartyAccessToken();

        // 2. 使用 Ticket 和 AccessToken 获取用户信息
        JSONObject userInfoResult = getThirdPartyUserInfo(ticket, accessToken);
        String thirdPartyUserId = userInfoResult.getString("user_id");
        String name = userInfoResult.getString("name");

        if (thirdPartyUserId == null) {
            throw new ServiceException("从第三方获取用户信息失败，未找到user_id");
        }

        // 3. 根据第三方用户ID查找本地用户
        SysUser user = userMapper.selectUserByThirdPartyUserId(thirdPartyUserId);

        // 4. 如果用户不存在，则创建新用户
        if (user == null) {
            log.info("第三方用户 {} 首次登录，开始创建本地账户...", thirdPartyUserId);
            user = createNewUser(thirdPartyUserId, name);
        }

        // 5. 使用若依的登录服务为用户生成Token
        return loginService.login(user.getUserName(), "123456");
    }

    private String getThirdPartyAccessToken() throws Exception {
        // --- 修复点 1: 清理配置参数 ---
        // 使用 .trim() 移除从配置文件加载的 appId 和 appKey 可能存在的首尾空格
        String cleanAppId = this.appId.trim();
        String cleanAppKey = this.appKey.trim();

        // --- 修复点 2: 增加详细的调试日志 ---
        String timeStamp = String.valueOf(System.currentTimeMillis());
        String stringToSign = cleanAppId + cleanAppKey + timeStamp;

        // --- 修复点 3: 调用标准、可靠的加密工具类 ---
        // 请确保您项目中有一个名为 HMACSHA1Util.java 的文件，内容是我之前提供给您的版本
        String keyInfo = HMACSHA1Util.sign(stringToSign, cleanAppKey);

        // 打印所有参与计算的变量，这是调试的关键！
        log.info("--- [SSO认证-Java端] 签名计算过程 ---");
        log.info("从配置加载的原始 appId: '{}'", this.appId);
        log.info("清理后的 appId (cleanAppId): '{}'", cleanAppId);
        log.info("清理后的 appKey (cleanAppKey): '{}...{}'", cleanAppKey.substring(0, 4), cleanAppKey.substring(cleanAppKey.length() - 4)); // 为安全不打印完整Key
        log.info("时间戳 (timeStamp): '{}'", timeStamp);
        log.info("待签名的字符串 (stringToSign): '{}'", stringToSign);
        log.info("最终生成的签名 (keyInfo): '{}'", keyInfo);
        log.info("请求的URL (tokenUrl): '{}'", tokenUrl);
        log.info("------------------------------------");

        JSONObject params = new JSONObject();
        params.put("appId", cleanAppId);    // 使用清理后的 appId
        params.put("timeStamp", timeStamp);
        params.put("keyInfo", keyInfo);

        String jsonPayload = params.toJSONString();
        log.info("即将发送的POST请求体: {}", jsonPayload);

        // --- 修复点 4: 检查 HttpUtils ---
        // 请再次确认您的 HttpUtils.java 在发送POST请求时，已强制添加了 Content-Type: application/json
        String response = HttpUtils.sendPost(tokenUrl, jsonPayload, MediaType.APPLICATION_JSON_UTF8_VALUE);

        log.info("获取AccessToken的原始响应: {}", response);

        if (response == null || response.isEmpty()) {
            throw new ServiceException("获取AccessToken失败，HTTP响应为空。请检查网络连接或对方服务器状态。");
        }

        JSONObject jsonResponse = JSON.parseObject(response);
        if (!"000000".equals(jsonResponse.getString("retCode"))) {
            log.error("获取AccessToken失败, 完整响应: {}", response);
            throw new ServiceException("获取AccessToken失败: " + jsonResponse.getString("retDesc"));
        }
        return jsonResponse.getJSONObject("tokenInfo").getString("accessToken");
    }

    private JSONObject getThirdPartyUserInfo(String ticket, String accessToken) {
        String url = userInfoUrl + "?ticket=" + ticket + "&accessToken=" + accessToken;
        String response = HttpUtils.sendGet(url);
        log.debug("获取用户信息响应: {}", response);

        JSONObject jsonResponse = JSON.parseObject(response);
        if (!"000000".equals(jsonResponse.getString("code"))) {
            throw new ServiceException("验证Ticket获取用户信息失败: " + jsonResponse.getString("message"));
        }
        return jsonResponse.getJSONObject("result");
    }

    private SysUser createNewUser(String thirdPartyUserId, String nickName) {
        SysUser newUser = new SysUser();
        // 设置第三方ID
        newUser.setThirdPartyUserId(thirdPartyUserId);
        // 用户名使用第三方ID，保证唯一性
        newUser.setUserName(nickName);
        newUser.setNickName(nickName);

        // **重要**: 需要设置默认值
        newUser.setDeptId(103L); // TODO: 请设置为一个默认的部门ID
        Long[] roleIds = {2L}; // TODO: 请设置为一个默认的角色ID (例如：普通角色)
        newUser.setRoleIds(roleIds);

        // 设置一个默认的、随机生成的密码，因为若依的登录逻辑需要密码字段
        // 用户实际上并不需要知道这个密码，因为他们总是通过SSO登录
        String randomPassword = "123456";
        newUser.setPassword(SecurityUtils.encryptPassword(randomPassword));
        newUser.setPwdUpdateDate(new Date());
        newUser.setCreateBy("system-sso"); // 设置创建者

        // 插入数据库
        userMapper.insertUser(newUser);
        // TODO: 根据若依的版本，可能需要手动插入 sys_user_role 关联表
        // 如果你的 insertUser 没有处理关联表，需要在这里添加关联
        // 例如： userRoleMapper.batchUserRole(...)
        return userMapper.selectUserByUserName(newUser.getUserName());
    }
}
